package com.mademoisellegeek.carrentalsimulation;

import com.mademoisellegeek.carrentalsimulation.enums.SortMethod;
import java.util.ArrayList;
import java.util.Map;

public class Optimiser {

    static String NB_OF_REQUESTS = "nbRequests";
    static String DAYS_OF_REQUESTS = "daysOfRequests";

    public static void updateOptimisationData(OptimisationData data, Vehicle availableVehicle, Travel request, Garage arrivalGarage) throws CarRentalException{
        int startDay = request.getStartDay();
        int endDay = request.getEndDay();

        Garage departureGarage = data.getGarage(availableVehicle.getGarageIdForDay(startDay));
        availableVehicle.saveTravel(startDay, endDay, arrivalGarage.getId());
        data.addVehicle(availableVehicle.getId(), (Vehicle) availableVehicle.clone());
        departureGarage.saveHire(startDay);
        arrivalGarage.saveReturn(endDay);
        data.addGarage(departureGarage.getId(), (Garage) departureGarage.clone());
        data.addGarage(arrivalGarage.getId(), (Garage) arrivalGarage.clone());
    }

    public static Vehicle getAvailableVehicle(OptimisationData data, String town, int startDay) {
        int garageId = getAnyGarageWithAvailableVehicle(data.getGarageDictionary(), town, startDay);
        if (garageId != 0) {
            return getAnyAvailableVehicleInGarage(garageId, startDay, data.getVehicleDictionary());
        }
        return null;
    }

    public static Vehicle getAvailableVehicleOptimised(OptimisationData data, String town, int startDay) {
        int garageId = getGarageWithMostAvailableVehicles(data.getGarageDictionary(), town, startDay);
        if (garageId != 0) {
            return getAnyAvailableVehicleInGarage(garageId, startDay, data.getVehicleDictionary());
        }
        return null;
    }

    public static Garage getAnyGarageWithAvailableSpace(Map<Integer, Garage> garageDictionary, String town, int endDay) {
        for (Garage garage : garageDictionary.values()) {
            if (garage.getTown().equals(town) && garage.getMinAvailableSpacesFromDay(endDay) > 0) {
                return garage;
            }
        }
        return null;
    }

    public static Garage getGarageWithMostAvailableSpaces(Map<Integer, Garage> garageDictionary, String town, int endDay) {
        Garage result = null;
        int availableSpaces = 0;
        for (Garage garage : garageDictionary.values()) {
            if (garage.getTown().equals(town) && garage.getMinAvailableSpacesFromDay(endDay) > availableSpaces) {
                availableSpaces = garage.getMinAvailableSpacesFromDay(endDay);
                result = garage;
            }
        }
        return result;
    }

    public static String findTownWithMostAvailableVehicles(OptimisationData data, ArrayList<String> towns, int startDay) {
        int availableVehicles = 0;
        String result = null;
        for (String town : towns) {
            for (Garage garage : data.getGaragesInTown(town)) {
                if (garage.getMinOccupiedSpacesFromDay(startDay) > availableVehicles) {
                    availableVehicles = garage.getMinOccupiedSpacesFromDay(startDay);
                    result = town;
                }
            }
        }
        return result;
    }

    public static String findTownWithMostAvailableSpaces(OptimisationData data, ArrayList<String> towns, int endDay) {
        int availableSpaces = 0;
        String result = null;
        for (String town : towns) {
            for (Garage garage : data.getGaragesInTown(town)) {
                if (garage.getMinAvailableSpacesFromDay(endDay) > availableSpaces) {
                    availableSpaces = garage.getMinAvailableSpacesFromDay(endDay);
                    result = town;
                }
            }
        }
        return result;
    }

    public static int getNumberOfDays(ArrayList<Travel> travelList) {
        int result = 0;
        for (Travel travel : travelList) {
            result += travel.getEndDay() - travel.getStartDay() + 1;
        }
        return result;
    }

    public static void sortRequestList(OptimisationData data, SortMethod method) {
        switch (method) {
            case START_DATE:
                data.sortRequestListByStartDay();
                break;
            case END_DATE:
                data.sortRequestListByEndDay();
                break;
            case LONGEST_FIRST:
                data.sortRequestListByLongestTravel();
                break;
            case SHORTEST_FIRST:
                data.sortRequestListByShortestTravel();
                break;
        }
    }

    private static int getAnyGarageWithAvailableVehicle(Map<Integer, Garage> garageDictionary, String town, int startDay) {
        for (Garage garage : garageDictionary.values()) {
            if (garage.getTown().equals(town) && garage.getMinOccupiedSpacesFromDay(startDay) > 0) {
                return garage.getId();
            }
        }
        return 0;
    }

    private static int getGarageWithMostAvailableVehicles(Map<Integer, Garage> garageDictionary, String town, int startDay) {
        int result = 0;
        int availableVehicles = 0;
        for (Garage garage : garageDictionary.values()) {
            if (garage.getTown().equals(town) && garage.getMinOccupiedSpacesFromDay(startDay) > availableVehicles) {
                availableVehicles = garage.getMinOccupiedSpacesFromDay(startDay);
                result = garage.getId();
            }
        }
        return result;
    }

    private static Vehicle getAnyAvailableVehicleInGarage(int garageId, int startDay, Map<Integer, Vehicle> carDictionary) {
        for (Vehicle vehicle : carDictionary.values()) {
            if (vehicle.getGarageIdForDay(startDay) == garageId) {
                return vehicle;
            }
        }
        return null;
    }
}